/* 
 * Copyright (c) 2012 JSquirrelEngine
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 */

package org.jsquirrel.rendering.LWJGLimpl;

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

import org.jsquirrel.geometry.Polygon;
import org.jsquirrel.geometry.VertexIterator;
import org.jsquirrel.math.F2Vector;
import org.jsquirrel.rendering.Color4F;
import org.jsquirrel.rendering.Graphics;
import org.jsquirrel.rendering.RenderingException;
import org.lwjgl.opengl.GL11;

/**
 * 
 * @author Juan David Adarve Bermudez
 *
 */
public class LWJGL_Graphics extends Graphics {
	
	//*********************************************************************************************
	// INSTANCE ATTRIBUTES
	//*********************************************************************************************
	
	protected float depth;
	
	
	//*********************************************************************************************
	// CONSTRUCTORS
	//*********************************************************************************************
	
	public LWJGL_Graphics() {
		depth = 0;
	}
	
	
	//*********************************************************************************************
	// PUBLIC METHODS
	//*********************************************************************************************

	@Override
	public void setColor3f(float red, float green, float blue) {
		GL11.glColor3f(red, green, blue);	
	}
	
	@Override
	public void setColor4f(float red, float green, float blue, float alpha) {
		GL11.glColor4f(red, green, blue, alpha);
	}
	
	@Override
	public void setDepth(float depth) {
		this.depth = depth;
	}
	
	@Override
	public void setLineWidth(float width) {
		GL11.glLineWidth(width);
	}
	
	@Override
	public void setPointSize(float size) {
		GL11.glPointSize(size);
	}

	@Override
	public void drawPolygon(Polygon p) {
		
		if(p == null) {
			throw new NullPointerException("LWJGL_Graphics.drawPolygon(): null polygon");
		}
		
		VertexIterator it = p.getIterator();
		
		switch(p.length()) {
		
			// no vertex
			case 0:
				return;
				
			// a point
			case 1:
				drawPoint(it.next());
				return;
				
			// a line
			case 2:
				F2Vector v1 = it.next();
				F2Vector v2 = it.next();
				drawLine(v1, v2);
				return;
			
			// a polygon
			default:
				
		}
		
		GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
		GL11.glBegin(GL11.GL_POLYGON);
		
			F2Vector v;
		
			while(it.hasNext()) {
				v = it.next();
				GL11.glVertex3f(v.x, v.y, depth);
			}
			
		GL11.glEnd();
	}
	
	@Override
	public void drawRectangle(float x0, float y0, float width, float height) {
		
		GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
		GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex3f(x0, y0, depth);
			GL11.glVertex3f(x0 + width, y0, depth);
			GL11.glVertex3f(x0 + width, y0 + height, depth);
			GL11.glVertex3f(x0, y0 + height, depth);
		GL11.glEnd();
	}


	@Override
	public void drawRectangle(F2Vector bottomLeft, F2Vector upperRight) {
		
		if(bottomLeft == null || upperRight == null) {
			throw new NullPointerException("LWJGL_Graphics.drawRectangle(F2Vector, F2Vector): null parameter: " +
					"bottomLeft " + bottomLeft + " upperRight " + upperRight);
		}
		
		GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
		GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex3f(bottomLeft.x, bottomLeft.y, depth);
			GL11.glVertex3f(upperRight.x, bottomLeft.y, depth);
			GL11.glVertex3f(upperRight.x, upperRight.y, depth);
			GL11.glVertex3f(bottomLeft.x, upperRight.y, depth);
		GL11.glEnd();
	}

	@Override
	public void fillPolygon(Polygon p) {
		
		if(p == null) {
			throw new NullPointerException("LWJGL_Graphics.fillPolygon(): null polygon");
		}
		
		// if the parameter does not form a triangle at least
		if(p.length() < 3) {
			return;
		}
		
		GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
		GL11.glBegin(GL11.GL_POLYGON);
		
			VertexIterator it = p.getIterator();
			F2Vector v;
		
			while(it.hasNext()) {
				v = it.next();
				GL11.glVertex3f(v.x, v.y, depth);
			}
		
		GL11.glEnd();
	}
	
	@Override
	public void drawPoint(float x, float y) {
		
		GL11.glBegin(GL11.GL_POINTS);
			GL11.glVertex3f(x, y, depth);
		GL11.glEnd();
	}
	
	@Override
	public void drawPoint(F2Vector v) {
		
		GL11.glBegin(GL11.GL_POINTS);
			GL11.glVertex3f(v.x, v.y, depth);
		GL11.glEnd();
	}
	
	@Override
	public void drawLine(float x1, float y1, float x2, float y2) {
		GL11.glBegin(GL11.GL_LINES);
			GL11.glVertex3f(x1, y1, depth);
			GL11.glVertex3f(x2, y2, depth);
		GL11.glEnd();
	}
	
	@Override
	public void drawLine(F2Vector v1, F2Vector v2) {
		
		if(v1 == null || v2 == null) {
			throw new NullPointerException("LWJGL_Graphics.drawLine(F2Vector, F2Vector): null vector: v1: " + v1 + " v2: " + v2);
		}
		
		GL11.glBegin(GL11.GL_LINES);
			GL11.glVertex3f(v1.x, v1.y, depth);
			GL11.glVertex3f(v2.x, v2.y, depth);
		GL11.glEnd();
	}


	
	public int createTexture(	String textureSource, Color4F texBgColor,
								boolean scaleSource,
								int MaxFilter,
								int minFilter) throws RenderingException, IOException {
		
		if(textureSource == null) {
			throw new NullPointerException("LWJGL_Graphics.createTexture(): null texture source");
		}
		
		URL url = LWJGL_Graphics.class.getClassLoader().getResource(textureSource);
		if(url == null) {
			throw new IOException("LWJGL_Graphics.createTexture(): cannot find texture source: " + textureSource);
		}
		
		BufferedImage bImage = ImageIO.read(url);
		if(bImage == null) {
			throw new IOException("LWJGL_Graphics.createTexture(): cannot load texture source: " + url.toString());
		}
		
		// computing the texture width and height as a power of 2
		int textureWidth = (int)Math.pow(2, Math.ceil(Math.log(bImage.getWidth())/Math.log(2)));
		int textureHeight = (int)Math.pow(2, Math.ceil(Math.log(bImage.getHeight())/Math.log(2)));
		
		int GLColorModel;
		int channelNum;
		boolean hasAlpha;
		if(bImage.getColorModel().hasAlpha()) {
			GLColorModel = GL11.GL_RGBA;
			channelNum = 4;
			hasAlpha = true;
		} else {
			GLColorModel = GL11.GL_RGB;
			channelNum = 3;
			hasAlpha = false;
		}
		
		WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, textureWidth, textureHeight, channelNum, null);
		
		return 0;
	}
	
	

}
